package com.nami.conver.domain.gchat.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import com.nami.conver.domain.gchat.service.GrpConverDomainService;
import com.nami.conver.domain.handler.ConverSyncHandler;
import com.nami.conver.domain.pchat.convertor.ConverConvert;
import com.nami.conver.domain.pchat.model.ConverModel;
import com.nami.conver.domain.pchat.model.UpdConverModel;
import com.nami.conver.domain.repository.CacheConverRepository;
import com.nami.conver.domain.repository.ConverRepository;
import com.nami.conver.domain.gateway.GrpMemberGateWay;
import com.nami.conver.types.util.ConverUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;


@Slf4j
@Component
@RequiredArgsConstructor
public class GrpConverDomainServiceImpl implements GrpConverDomainService {

    private final ConverRepository converRepository;
    private final CacheConverRepository cacheConverRepository;
    private final ConverSyncHandler syncHandler;
    private final GrpMemberGateWay grpMemberRepository;


    private ConverModel getConverFromCacheOrDB(String appKey, String senderId, String receiverId) {
        ConverModel converDomain = cacheConverRepository.get(appKey, senderId, receiverId);
        if (converDomain == null) {
            ConverModel conversation = converRepository.getConversation(appKey, senderId, receiverId);
            if (conversation == null) {
                return null;
            }
            cacheConverRepository.writeConver(conversation);
            return conversation;
        }

        return converDomain;
    }

    @Override
    public void refreshConvers(UpdConverModel converMsgModel) {
        // 刷新我自己会话
        final ConverModel converMe = cacheConverRepository
            .get(ConverUtil.genLocalCacheConverKey(converMsgModel.getAppKey(),
            converMsgModel.getSenderId(), converMsgModel.getReceiverId()));
        if (null == converMe) {
            ConverModel conversation = this.getConverFromCacheOrDB(converMsgModel.getAppKey(),
                converMsgModel.getSenderId(), converMsgModel.getReceiverId());

            ConverModel needAdd = new ConverModel();
            needAdd.setAppKey(converMsgModel.getAppKey());
            needAdd.setConverType(2);
            needAdd.setUserId(converMsgModel.getSenderId());
            needAdd.setTargetId(converMsgModel.getReceiverId());
            needAdd.setLatestReadMsgIndex(0L);
            needAdd.setIfMute(Boolean.FALSE);
            needAdd.setIfTop(Boolean.FALSE);

            needAdd.setLatestMsgId(converMsgModel.getMessageId());
            needAdd.setLatestUnreadMsgIndex(converMsgModel.getSeq());
            needAdd.setSyncTime(converMsgModel.getTime());
            needAdd.setSortTime(converMsgModel.getTime());
            if (conversation != null) {
                needAdd.setIfMute(conversation.getIfMute());
                needAdd.setIfTop(conversation.getIfTop());

                needAdd.setTopUpdatedTime(conversation.getTopUpdatedTime());

                if (conversation.getLatestUnreadMsgIndex() != null
                    && conversation.getLatestUnreadMsgIndex() > converMsgModel.getSeq()) {
                    needAdd.setLatestMsgId(conversation.getLatestMsgId());
                    needAdd.setLatestUnreadMsgIndex(conversation.getLatestUnreadMsgIndex());
                    needAdd.setSyncTime(conversation.getSyncTime());
                    needAdd.setSortTime(conversation.getSortTime());
                    log.warn("[c2g] 更新我的会话出现问题，数据库数据为最新数据。");
                }

                needAdd.setLatestReadMsgId(conversation.getLatestReadMsgId());
                needAdd.setLatestReadMsgIndex(conversation.getLatestReadMsgIndex());
            }
            cacheConverRepository.insertOrUpd(ConverUtil.genLocalCacheConverKey(converMsgModel.getAppKey(),
                converMsgModel.getSenderId(), converMsgModel.getReceiverId()), needAdd);
//            syncHandler.writeNow(ConverUtil.genLocalCacheConverKey(converMsgModel.getAppKey(),
//            converMsgModel.getSenderId(), converMsgModel.getReceiverId()));
            syncHandler.handler(ConverUtil.genLocalCacheConverKey(converMsgModel.getAppKey(),
                converMsgModel.getSenderId(), converMsgModel.getReceiverId()));
            return;
        }
        ConverModel updConver = converMe.clone();
        updConver.setLatestMsgId(converMsgModel.getMessageId());
        updConver.setLatestUnreadMsgIndex(converMsgModel.getSeq());
        updConver.setSyncTime(converMsgModel.getTime());
        updConver.setSortTime(converMsgModel.getTime());
        cacheConverRepository.insertOrUpd(ConverUtil.genLocalCacheConverKey(converMsgModel.getAppKey(),
            converMsgModel.getSenderId(), converMsgModel.getReceiverId()), updConver);
//        syncHandler.writeNow(ConverUtil.genLocalCacheConverKey(converMsgModel.getAppKey(), converMsgModel.getSenderId(), converMsgModel.getReceiverId()));
        syncHandler.handler(ConverUtil.genLocalCacheConverKey(converMsgModel.getAppKey(),
            converMsgModel.getSenderId(), converMsgModel.getReceiverId()));

        // 此处需要反复修改 处于临界状态 条件问题
        List<String> memberUserIds = grpMemberRepository.findMemberUserIdsByGrpId(converMsgModel.getReceiverId());

        List<String> needQuery = new ArrayList<>();
        // 刷新缓存
        ConverModel refresh = null;
        for (String memberUserId : memberUserIds) {
            if (memberUserId.equals(converMsgModel.getSenderId())) {
                continue;
            }
            final ConverModel converItem = cacheConverRepository.get(ConverUtil
                .genLocalCacheConverKey(converMsgModel.getAppKey(), memberUserId,
                    converMsgModel.getReceiverId()));
            if (null == converItem) {
                needQuery.add(memberUserId);
                continue;
            }

            if (converItem.getLatestUnreadMsgIndex() != null
                && converItem.getLatestUnreadMsgIndex() > converMsgModel.getSeq()) {
//                log.warn("[c2g] 会话更新失败，当前消息非最新消息，messageId={} seq={}, cacheMaxSeq={}", message.getId(),
//                    message.getSeq(), converItem.getLatestUnreadMsgIndex());
                continue;
            }
            refresh = new ConverModel();
            refresh.setId(converItem.getId());
            refresh.setAppKey(converItem.getAppKey());
            refresh.setUserId(converItem.getUserId());
            refresh.setTargetId(converItem.getTargetId());

            refresh.setLatestMsgId(converMsgModel.getMessageId());
            refresh.setLatestMsg(converMsgModel.getPayload());
            refresh.setSyncTime(converMsgModel.getTime());
            refresh.setSortTime(converMsgModel.getTime());
            refresh.setLatestUnreadMsgIndex(converMsgModel.getSeq());
            cacheConverRepository.insertOrUpd(ConverUtil.genLocalCacheConverKey(converMsgModel.getAppKey(),
                memberUserId, converMsgModel.getReceiverId()), refresh);
            syncHandler.handler(ConverUtil.genLocalCacheConverKey(converMsgModel.getAppKey(),
                memberUserId, converMsgModel.getReceiverId()));

//            converSyncHandler.handler(newConverBrief(appKey, member.getUserId(), message.getReceiverId()));
        }

        if (CollUtil.isEmpty(needQuery)) {
            return;
        }
        List<ConverModel> conversations = this.getConversFromCacheOrDB(converMsgModel.getAppKey(),
            needQuery,
            converMsgModel.getReceiverId());
        Map<String, ConverModel> converMap = new HashMap<>();
        if (CollUtil.isNotEmpty(conversations)) {
            converMap = conversations.stream().collect(Collectors.toMap(ConverModel::getUserId,
                Function.identity()));
        }
        ConverModel converItem;
        for (String userId : needQuery) {
            converItem = new ConverModel();
            converItem.setConverType(2);
            converItem.setAppKey(converMsgModel.getAppKey());
            converItem.setUserId(userId);
            converItem.setTargetId(converMsgModel.getReceiverId());

            ConverModel dbConver = converMap.get(userId);
            if (dbConver == null) {
                // 如果数据库没有，再次新建会话
                // 此处是新建会话，已读index 待处理
                converItem.setIfMute(Boolean.FALSE);
                converItem.setIfTop(Boolean.FALSE);

                converItem.setLatestMsgId(converMsgModel.getMessageId());
                converItem.setSyncTime(converMsgModel.getTime());
                converItem.setSortTime(converMsgModel.getTime());
                converItem.setLatestUnreadMsgIndex(converMsgModel.getSeq());
                // qq 删除会话 会将会话中未读消息已读，并不删除服务端存储的会话，退群，客户端删除会话才会真正删除。所以不退群，不存在会话不存在，这种是极端情况。
                // 会话从客户端列表删除后，再次发来消息， 此时为客户端调用sdk将未读数置0，全部已读
//                converItem.setLatestReadMsgIndex(message.getSeq() - 1);
//                converItem.setLatestReadMsgTime(message.getTime()); // 或者为0
                cacheConverRepository.insertOrUpd(ConverUtil.genLocalCacheConverKey(converItem.getAppKey(),
                    converItem.getUserId(), converItem.getTargetId()), converItem);
//                converSyncHandler.handler(newConverBrief(appKey, converItem.getUserId(), converItem.getTargetId()));
                syncHandler.handler(ConverUtil.genLocalCacheConverKey(converMsgModel.getAppKey(),
                    converItem.getUserId(), converItem.getTargetId()));
                continue;
            }

            converItem.setId(dbConver.getId());
            converItem.setSyncTime(converMsgModel.getTime());
            converItem.setSortTime(converMsgModel.getTime());

            if (dbConver.getLatestUnreadMsgIndex() != null
                && dbConver.getLatestUnreadMsgIndex() > converMsgModel.getSeq()) {
//                log.warn("[c2g] 会话更新失败，当前消息非最新消息，messageId={} seq={}, cacheMaxSeq={}", message.getId(),
//                    message.getSeq(), converItem.getLatestUnreadMsgIndex());
                converItem.setLatestMsgId(dbConver.getLatestMsgId());
                converItem.setLatestUnreadMsgIndex(dbConver.getLatestUnreadMsgIndex());
                converItem.setSyncTime(dbConver.getSyncTime());
                converItem.setSortTime(dbConver.getSortTime());
            }
            // 此处找不到比较对象，只能从数据取默认的。
            converItem.setLatestReadMsgIndex(dbConver.getLatestReadMsgIndex());
            converItem.setLatestReadMsgTime(dbConver.getLatestReadMsgTime());
            converItem.setLatestReadMsgId(dbConver.getLatestReadMsgId());

            cacheConverRepository.insertOrUpd(ConverUtil.genLocalCacheConverKey(converItem.getAppKey(),
                converItem.getUserId(), converItem.getTargetId()), converItem);
            syncHandler.handler(ConverUtil.genLocalCacheConverKey(converItem.getAppKey(),
                converItem.getUserId(), converItem.getTargetId()));
        }
    }

    public List<ConverModel> getConversFromCacheOrDB(String appKey, List<String> userIds, String targetId) {
        TimeInterval timer = DateUtil.timer();
        List<ConverModel> cacheList = cacheConverRepository.getConversByGrpView(appKey,
            userIds, targetId);
        if (CollUtil.isNotEmpty(cacheList)) {
            if (cacheList.size() == userIds.size()) {
                return ConverConvert.INSTANCE.convertList(cacheList);
            }
            List<ConverModel> cacheConvers = ConverConvert.INSTANCE.convertList(cacheList);
            List<String> cacheUserIds = cacheList.stream()
                .map(ConverModel::getUserId)
                .collect(Collectors.toList());
//            userId.removeAll(cacheUserIds);
            List<String> qryIds = userIds.stream()
                .filter(item -> !cacheUserIds.contains(item))
                .collect(Collectors.toList());
            List<ConverModel> dbConvers = converRepository.qryConversByGrpMembers(appKey,
                qryIds, targetId);
            if (CollUtil.isNotEmpty(dbConvers)) {
                cacheConverRepository.writeAll(ConverConvert.INSTANCE.convertList(dbConvers));
                cacheConvers.addAll(ConverConvert.INSTANCE.convertList(dbConvers));
                return cacheConvers;
            }

        }
        List<ConverModel> conversByUserIds = converRepository.qryConversByGrpMembers(appKey,
            userIds, targetId);
        if (CollUtil.isNotEmpty(conversByUserIds)) {
            cacheConverRepository.writeAll(ConverConvert.INSTANCE.convertList(conversByUserIds));
        }
        if (timer.interval() > 300) {
            log.warn("[conver-batch] 批量获取缓存出现问题， appKey={}, targetId={} use:{}ms",
                appKey, targetId, timer.interval());
        }

        return ConverConvert.INSTANCE.convertList(conversByUserIds);
    }


}
